#include <cstdio>
#include <stdlib.h>
#include <assert.h>

#include "EPollPoller.h"
#include "Channel.h"

int createEpollfd() {
    int epfd = ::epoll_create1(EPOLL_CLOEXEC);
    if (epfd < 0) {
        printf("create epollFd fail");
        abort();
    }
    return epfd;
}

EPollPoller::EPollPoller(EventLoop* loop) :
    loop_(loop),
    epollFd_(createEpollfd()),
    events_(kEventListInitLength)
    {
    }

void EPollPoller::poll(int timeoutMs, ChannelList& activeChannelList) {
    int ret = ::epoll_wait(epollFd_, events_.data(), events_.size(), timeoutMs);
    if (ret > 0) {
        for (int i = 0; i < ret; i++) {
            activeChannelList.push_back(static_cast<Channel*>(events_[i].data.ptr));
            activeChannelList[i]->setREvent(events_[i].events);
        }
        if (ret == events_.size()) {
            events_.resize(events_.size() * 2);
        }
    } else if (ret == 0) {
        printf("nothing happen\n");
    } else {
        if (errno != EINTR) {
            printf("epoll_wait fail\n");
            abort();
        }
    }
    
}

void EPollPoller::updateChannel(Channel* channel) {
    if (channel->getState() == Channel::NEW || channel->getState() == Channel::DELETED) {
        epoll_event event;
        update(EPOLL_CTL_ADD, channel);
        channel->setState(Channel::ADDED);
    } else { // state == added
        if (channel->isNoneEvent()) { 
            update(EPOLL_CTL_DEL, channel);
            channel->setState(Channel::DELETED);
        } else {
            update(EPOLL_CTL_MOD, channel);
        }
    }
}

void EPollPoller::removeChannel(Channel* channel) {
    assert(channel->isNoneEvent());
    // 因为没有存channel列表，所以不用做什么
}

void EPollPoller::update(int op, Channel* channel) {
    epoll_event event;
    event.events = channel->getEvents();
    event.data.ptr = channel;
    int ret = ::epoll_ctl(epollFd_, op, channel->getFd(), &event);
    if (ret < 0) {
        printf("epoll_ctl fail");
        abort();
    }
}